home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / source / dbu / modify.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-18  |  41.3 KB  |  1,698 lines

  1. # include    <stdio.h>
  2. # include    <ingres.h>
  3. # include    <pv.h>
  4. # include    <aux.h>
  5. # include    <access.h>
  6. # include    <batch.h>
  7. # include    <lock.h>
  8. # include    <opsys.h>
  9. # include     <func.h>
  10. # include    <version.h>
  11. # include    <symbol.h>
  12. # include    <catalog.h>
  13. # include    <btree.h>
  14. # include    <sccs.h>
  15. # include    <errors.h>
  16.  
  17. SCCSID(@(#)modify.c    8.8    5/7/85)
  18.  
  19. extern    short    tTdbu[];
  20. extern    int    modify();
  21. extern     int    null_fn();
  22. extern  char    *iocv();
  23.  
  24. struct fn_def ModifyFn =
  25. {
  26.     "MODIFY",
  27.     modify,
  28.     null_fn,
  29.     null_fn,
  30.     NULL,
  31.     0,
  32.     tTdbu,
  33.     100,
  34.     'Z',
  35.     0
  36. };
  37.  
  38. /*
  39. **  MODIFY -- converts any relation to the specified
  40. **        storage structure
  41. **
  42. **    arguments:
  43. **    0 - relation name
  44. **    1 - storage structure ("heap", "cheap", "hash", "chash",
  45. **        "isam", "cisam")
  46. **    2 - "name" for attribute names, or "num" for numbers
  47. **    3 - key1
  48. **    4 - key2
  49. **        .
  50. **        .
  51. **    i - null
  52. **    i+1 - option name (e.g., "fillfactor")
  53. **    i+2 - option value
  54. **        .
  55. **        .
  56. **
  57. **    If all the options default, parameter i -> pc are omitted.
  58. **    If no keys are provided, parameter 2 is omitted.
  59. */
  60.  
  61. int        F_fac, Mn_pages, Mx_pages;
  62. char        Lid[MAXLID][MAXNAME];
  63. int        NLidKeys;
  64. int        LidKey[MAXLID];
  65.  
  66. struct modtab
  67. {
  68.     char    *type;
  69.     char    newrelspec;
  70.     char    yeskeys;
  71.     char    sortit;
  72.     char    yes_seq;
  73.     int    f_fac;
  74.     int    mn_pages;
  75.     int    mx_pages;
  76. };
  77.  
  78.  
  79. struct modtab    Modtab[] =
  80. {
  81.     /* type        spec    keys    sort    seq    ffac    min    max */
  82.  
  83.     "heap",        M_HEAP,    FALSE,    FALSE,    FALSE,    0,    0,    0,
  84.     "cheap",    -M_HEAP,FALSE,    FALSE,    FALSE,    0,    0,    0,
  85.     "hash",        M_HASH,    TRUE,    TRUE,    FALSE,    50,    10,    -1,
  86.     "chash",    -M_HASH,TRUE,    TRUE,    FALSE,    75,    1,    -1,
  87.     "isam",        M_ISAM,    TRUE,    TRUE,    FALSE,    80,    0,    0,
  88.     "cisam",    -M_ISAM,TRUE,    TRUE,    FALSE,    100,    0,    0,
  89.     "heapsort",    M_HEAP,    TRUE,    TRUE,    TRUE,    0,    0,    0,
  90.     "cheapsort",    -M_HEAP,TRUE,    TRUE,    TRUE,    0,    0,    0,
  91.     "truncated",    M_TRUNC,FALSE,    FALSE,    FALSE,    0,    0,    0,
  92.     "ordered",    M_ORDER,TRUE,    FALSE,    FALSE,    0,    0,    0,
  93.     0
  94. };
  95.  
  96. struct mod_info
  97. {
  98.     char    outfile[MAXNAME + 4];    /* result file filled by ksort */
  99.     char    formfile[MAXNAME + 4];    /* file with descriptor for ksort */
  100.     char    infile[MAXNAME + 4];    /* input file for ksort (relation itself */
  101.     char    reltemp[MAXNAME + 4];    /* file holding new relation */
  102.     char    spfile[MAXNAME + 4], spflag;    /* isam spool file for overflow */
  103.     char    btree[MAXNAME + 4];    /* file holding temporary btree structure */
  104.     char    temp_sort[MAXNAME + 4];    /* file holding result of special isam
  105.                     ** required when ordering on a field
  106.                     */
  107. };
  108.  
  109. struct mod_info    Mod_info;
  110.  
  111. extern DESC Btreesec;
  112. extern int Btree_fd;
  113.  
  114.  
  115.  
  116. modify(pc, pv)
  117. int    pc;
  118. PARM    *pv;
  119. {
  120.     register int        i, j;
  121.     register char        *rname;
  122.     register struct modtab    *mp;
  123.     struct modtab        *p;
  124.     int            sorted, dim;
  125.     DESC            dold, dnew;
  126.     long            temptid;
  127.     extern int        Noupdt;
  128.     extern DESC        Attdes;
  129.     struct attribute    atttup, attkey;
  130.     TID            tid;
  131.     int            lidkey, numatts;
  132.     extern char        *trim_relname();
  133.  
  134.     
  135. #    ifdef xZTR1
  136.     if (tTf(34, -1))
  137.     {
  138.         printf("enter modify\n");
  139.         prvect(pc, pv);
  140.     }
  141. #    endif
  142.  
  143.     pv[pc].pv_val.pv_str = NULL;
  144.  
  145.     /* check for nice parameters */
  146.     if (pc < 2)
  147.         syserr("MODIFY: pc %d", pc);
  148.  
  149.     /* save relation name for error messages */
  150.     rname = (pv++)->pv_val.pv_str;    /* *pv now pointes to storage spec */
  151.  
  152.     /* check for good relation */
  153.     i = openr(&dold, OR_READ, rname);
  154.     if (i == AMOPNVIEW_ERR)
  155.         return (error(NOMODVIEW, rname, 0));
  156.     if (i > 0)
  157.         /* reln does not exist */
  158.         return (error(NOREL, rname, 0));    
  159.     else if (i < 0)
  160.         syserr("MODIFY: openr (%.14s) %d", rname, i);
  161.     /* can only modify a relation you own and isn't a sys rel */
  162.     
  163.     if (!bequal(Usercode, dold.reldum.relowner, UCODE_SZ))
  164.     {
  165.         i = NOOWN;
  166.     }
  167.     if ((dold.reldum.relstat & S_CATALOG) && Noupdt)
  168.     {
  169.         i = NOMODSYSREL;
  170.     }
  171.     if (i)
  172.     {
  173.         closer(&dold);
  174.         return (error(i, rname, 0));
  175.     }
  176.  
  177.     /*
  178.     ** Form descriptor for new relation. Here we need to
  179.     ** separate the pages from the old and new relations.
  180.     ** Since pages are identified by the TID of the relation
  181.     ** relation tuple, both old and new have the same identifiers.
  182.     ** To avoid this problem, a special TID is hand crafted for
  183.     ** the new relation.
  184.     */
  185.     bmove(&dold, &dnew, sizeof dnew);
  186.     dnew.reltid.s_tupid.line_id = (char) -2;    /* choose impossible reltid */
  187.     /* assume new relation isn't ordered */
  188.     if (dold.reldum.reldim)
  189.     {
  190.         dnew.reldum.relatts -= dold.reldum.reldim;
  191.         dnew.reldum.relwid -= dold.reldum.reldim * LIDSIZE;
  192.         dnew.reldum.reldim = 0;
  193.     }
  194.  
  195.     /* In case of an interrupt from a previous modify,
  196.     ** there might be pages around. Get rid of them.
  197.     */
  198.     cleanrel(&dnew);
  199.  
  200.     ingresname(dold.reldum.relid, dold.reldum.relowner, Mod_info.infile);
  201.     dim = 0;
  202.     NLidKeys = 0;
  203.  
  204.     /* scan for entry in relspec table */
  205.     for (mp = Modtab; mp->type; mp++)
  206.     {
  207.         if (bequal(mp->type, pv->pv_val.pv_str, 7) && bequal("ordered", pv->pv_val.pv_str, 7))
  208.         {
  209.             if ((dim = atoi(pv->pv_val.pv_str + 7)) <= 0 || dim > MAXLID)
  210.             {
  211.                 closer(&dold);
  212.                 return(error(BADORDDIM, rname, iocv(dim), 0));
  213.             }
  214.             break;
  215.         }
  216.         if (sequal(mp->type, pv->pv_val.pv_str))
  217.             break;
  218.     }
  219.  
  220.     /* if not found, error */
  221.     if (!mp->type)
  222.     {
  223.         closer(&dold);
  224.         return (error(BADSTORAGE, rname, pv->pv_val.pv_str, 0));    /* bad relspec */
  225.     }
  226.  
  227.     if (mp->newrelspec == M_ORDER && dold.reldum.relindxd == SECINDEX)
  228.     /* can't order an index relation */
  229.     {
  230.         closer(&dold);
  231.         return(error(NOORDINDX, rname,0));
  232.     }
  233.  
  234.     if (mp->newrelspec == M_ORDER)
  235.     {
  236.         dnew.reldum.reldim = dim;
  237.         for (i = 0; i < dim; ++i)
  238.         {
  239.             ++dnew.reldum.relatts;
  240.             dnew.relxtra[dnew.reldum.relatts] = 0;
  241.             dnew.reloff[dnew.reldum.relatts] = dnew.reldum.relwid;
  242.             dnew.relfrmt[dnew.reldum.relatts] = INT;
  243.             dnew.relfrml[dnew.reldum.relatts] = LIDSIZE;
  244.             dnew.reldum.relwid += LIDSIZE;
  245.         }
  246.         concat(BTREE, Fileset, Mod_info.btree);
  247.         create_btree(Mod_info.btree);
  248.         dnew.btree_fd = Btree_fd;
  249.         /* ok to order ascending/descending */
  250.         mp->yes_seq = TRUE;
  251.     }
  252.     else
  253.     {
  254.         dnew.reldum.relspec = mp->newrelspec;
  255.         if (dold.reldum.reldim)
  256.         {
  257.             dold.reldum.relatts -= dold.reldum.reldim;
  258.             dold.reldum.relwid -= dold.reldum.reldim * LIDSIZE;
  259.             dold.reldum.reldim = 0;
  260.             closer(dold.relbtree);
  261.             close(dold.btree_fd);
  262.         }
  263.     }
  264.  
  265.     if (dnew.reldum.relspec == M_TRUNC)
  266.         dnew.reldum.relspec = M_HEAP;
  267.  
  268.     pv++;    /* now points to first parameter */
  269.  
  270.     /* get the key domains information */
  271.     if ((i = getkeys(&pv, rname, &dnew, mp)) > 0)
  272.     {
  273.         closer(&dold);
  274.         return (i);    /* user error */
  275.     }
  276.  
  277.     j = 0;
  278.     for (i = 0; i < NLidKeys; ++i)
  279.         if (LidKey[i] > dold.reldum.relatts - dold.reldum.reldim)
  280.         {
  281.             j = 1;
  282.             break;
  283.         }
  284.  
  285.     if (!j && dold.reldum.reldim)
  286.     /* treat old relation as if not ordered since lid field not needed */
  287.     {
  288.         dold.reldum.relatts -= dold.reldum.reldim;
  289.         dold.reldum.relwid -= dold.reldum.reldim * LIDSIZE;
  290.         dold.reldum.reldim = 0;
  291.         closer(dold.relbtree);
  292.         close(dold.btree_fd);
  293.     }
  294.  
  295.     if (!dnew.reldum.reldim || !NLidKeys)
  296.     {
  297.         F_fac = mp->f_fac;
  298.         Mn_pages = mp->mn_pages;
  299.         Mx_pages = mp->mx_pages;
  300.     }
  301.     else
  302.     /* set parameters to that of storage type of relation to be ordered */
  303.     {
  304.         for (p = Modtab; p->type; p++)
  305.             if (dnew.reldum.relspec == p->newrelspec)
  306.                 break;
  307.         F_fac = p->f_fac;
  308.         Mn_pages = p->mn_pages;
  309.         Mx_pages = p->mx_pages;
  310.     }
  311.  
  312.     if (mp->newrelspec != M_ORDER)
  313.         for (i = 0; i < dnew.reldum.reldim; ++i)
  314.             Lid[i][0] = 0;
  315.     else
  316.         for (i = 1; i <= dnew.reldum.reldim; ++i)
  317.             concat("lid", iocv(i), Lid[i-1]);
  318.  
  319.     /* get fillfactor and other options if any */
  320.     if (i = getfill(&dnew, pv, rname, mp))
  321.     {
  322.         closer(&dold);
  323.         return (i);    /* user error */
  324.     }
  325.  
  326.     /* check for duplicate attribute name */
  327.     if (mp->newrelspec == M_ORDER)
  328.     {
  329.         opencatalog("attribute", OR_READ);
  330.         setkey(&Attdes, &attkey, dnew.reldum.relid, ATTRELID);
  331.         setkey(&Attdes, &attkey, dnew.reldum.relowner, ATTOWNER);
  332.         numatts = dold.reldum.relatts - dold.reldum.reldim;
  333.         for (i = 0; i < dnew.reldum.reldim; ++i)
  334.         {
  335.             setkey(&Attdes, &attkey, Lid[i], ATTNAME);
  336.             if (getequal(&Attdes, &attkey, &atttup, &tid) == 0)
  337.             {
  338.                 if (atttup.attid <= numatts)
  339.                 /* ok to duplicate attributes that will be removed */
  340.                 {
  341.                     closer(&dold);
  342.                     return(error(INVALIDATTR, rname, Lid[i], 0));
  343.                 }
  344.             }
  345.         }
  346.     }
  347.  
  348.     /* lock the relation relation */
  349.     if (Lockrel)
  350.     {
  351.         get_p_tid(&dold, &temptid);
  352.         setrll(A_SLP, temptid, M_EXCL);
  353.     }
  354.  
  355.     if (!dnew.reldum.reldim || NLidKeys > 0)
  356.         /* compute new relation parameters & build descriptor */
  357.         make_newrel(&dnew);
  358.  
  359.     if (sorted = ((mp->sortit || NLidKeys > 0) && (dold.reldum.reltups != 0)))
  360.     {
  361.         sortrel(&dold, &dnew);
  362.         dold.reldum.relindxd = 0;
  363.     }
  364.  
  365.     if (!dnew.reldum.reldim || NLidKeys > 0)
  366.         /* physically create the new relation */
  367.         if (formatpg(&dnew, dnew.reldum.relprim) != 0)
  368.             syserr("modify: formatpg");
  369.  
  370.     /* clear relgiven field; if heap remove any keys */
  371.     clearkeys(&dnew);
  372.  
  373.     if (abs(dnew.reldum.relspec) == M_HEAP)
  374.         for (i = 1; i <= dnew.reldum.relatts; i++)
  375.             dnew.relxtra[i] = 0;
  376.  
  377.     if (NLidKeys > 0 && dnew.reldum.relspec == M_ISAM)
  378.         sort_isam(&dold, &dnew);
  379.  
  380.     if (mp->newrelspec != M_TRUNC)
  381.         fill_rel(&dold, &dnew, sorted);
  382.  
  383.     closer(&dold);    /* error return is impossible */
  384.     if (abs(dnew.reldum.relspec) == M_ISAM && (!dnew.reldum.reldim || NLidKeys > 0))
  385.     {
  386.         j = dnew.reldum.reldim;
  387.         dnew.reldum.reldim = 0;
  388.         if (i = bldindex(&dnew))
  389.             syserr("bldindex: %.14s %d", dnew.reldum.relid, i);
  390.         dnew.reldum.reldim = j;
  391.         unspool(&dold, &dnew);
  392.     }
  393.  
  394.     /*
  395.     ** New relation is now complete. The system relations need to
  396.     ** be updated. First destroy all buffers with pages from the
  397.     ** new relation.
  398.     */
  399.     if (i = cleanrel(&dnew))
  400.         syserr("modify:clean new %d,%.14s", i, dnew.reldum.relid);
  401.  
  402.     fill_batch(&dold, &dnew);
  403.  
  404.     /*
  405.     ** Close the file for the new relation. This must be
  406.     ** done after the fill_batch in case we are modifing
  407.     ** the attribute relation.
  408.     */
  409.     if (!dnew.reldum.reldim || NLidKeys > 0)
  410.         close(dnew.relfp);
  411.     dnew.relopn = 0;
  412.     ruboff("modify");
  413.     modupdate();
  414.     if (mp->newrelspec == M_ORDER)
  415.     {
  416.         close(dnew.btree_fd);
  417.         make_bsec(dnew.reldum.relid, dim);
  418.     }
  419.     rubon();
  420.  
  421.     if (Lockrel)
  422.         unlrl(temptid);
  423.  
  424.     return (0);
  425. }
  426.  
  427.  
  428. /*
  429. **    GETKEYS - get key domains information
  430. **
  431. **    Parameters:
  432. **        ppv - parameter vector with info about keys
  433. **        relname - relation name
  434. **        d - new descriptor for the relation
  435. **        mp - mod table
  436. **
  437. **    Return Codes:
  438. **        0 - ok
  439. **        >0 - error from modseqkey        
  440. */
  441. getkeys(ppv, relname, d, mp)
  442. PARM        **ppv;
  443. char        *relname;
  444. register DESC    *d;
  445. struct modtab    *mp;
  446. {
  447.     register PARM        *pv;
  448.     register char        *cp;
  449.     int            namemode, sort_only, as_ds;
  450.     int            i, j, keyno, keywid;
  451.     struct attribute    attkey, atttup;
  452.     struct index        ikey, itup;
  453.     TID            tid;
  454.     extern DESC        Attdes, Inddes;
  455.  
  456.     pv = *ppv;    /* copy list of params */
  457.  
  458.     if (mp->newrelspec != M_ORDER)
  459.         /* zero key info (ordering does not change keyed fields) */
  460.         for (i = 0; i <= d->reldum.relatts; i++)
  461.             d->relxtra[i] = 0;
  462.     for (i = 0; i <= d->reldum.relatts; ++i)
  463.         d->relgiven[i] = 0;
  464.  
  465.     /* determine whether there are any keys at all */
  466.     keywid = 0;
  467.     keyno = 0;
  468.     sort_only = FALSE;
  469.     cp = pv->pv_val.pv_str;
  470.  
  471.     if (cp == (char *)NULL || *cp == (char *)NULL)
  472.     {
  473.         /* no key information. default as needed */
  474.         if (mp->yeskeys && mp->newrelspec != M_ORDER)
  475.         {
  476.             cp = "\1";    /* default to first key */
  477.             namemode = FALSE;
  478.         }
  479.         else
  480.             pv++;    /* point one to far */
  481.     }
  482.     else
  483.     {
  484.         /* check for name mode */
  485.         if (namemode = sequal(cp, "name"))
  486.         {
  487.  
  488.             /* check attribute names, and convert them to numbers */
  489.             opencatalog("attribute", OR_READ);
  490.             setkey(&Attdes, &attkey, Mod_info.infile, ATTRELID);
  491.             setkey(&Attdes, &attkey, Usercode, ATTOWNER);
  492.         }
  493.         pv++;    /* inc to next key */
  494.         cp = (pv++)->pv_val.pv_str;
  495.     }
  496.  
  497.     /* scan for attribute names */
  498.     for (; cp != NULL; cp = (pv++)->pv_val.pv_str)
  499.     {
  500.         /* check for separator between keys & options */
  501.         if (*cp == (char *)NULL)
  502.         {
  503.             pv++;    /* point two past NULL */
  504.             break;
  505.         }
  506.  
  507.         if (NLidKeys >= d->reldum.reldim && mp->newrelspec == M_ORDER)
  508.         {
  509.             /* more than one field specified as ordering key */
  510.             closeall(0l, 0l);
  511.             return(error(TOOMANYORDKEYS, relname, 0));
  512.         }
  513.  
  514.         if (namemode)
  515.         {
  516.             /* check for "sort only" attribute */
  517.             if (*cp == '#')
  518.             {
  519.                 cp++;    /* inc to start of name */
  520.                 sort_only = TRUE;
  521.             }
  522.  
  523.             /* check for ascending/descending modifier */
  524.             if ((as_ds = modseqkey(cp, relname, mp->yes_seq)) > 0)
  525.                 return (as_ds);    /* error */
  526.  
  527.             setkey(&Attdes, &attkey, cp, ATTNAME);
  528.             i = getequal(&Attdes, &attkey, &atttup, &tid);
  529.             if (i < 0)
  530.                 syserr("MODIFY: geteq(att) %d", i);
  531.             if (i > 0)
  532.             {
  533.                 closeall(0l, 0l);
  534.                 return (error(INVALIDATTR, relname, cp, 0));    /* bad att name */
  535.             }
  536.             i = atttup.attid;
  537.             if (i > d->reldum.relatts)
  538.             {
  539.                 /* attempting to key on lid field which will be
  540.                 ** removed
  541.                 */
  542.                 closeall(0l,0l);
  543.                 return(error(ATTRREMV, relname, cp, 0));
  544.             }
  545.         }
  546.         else
  547.         {
  548.             i = *cp;
  549.             as_ds = 0;
  550.         }
  551.  
  552.         keyno++;
  553.         /* add new key to descriptor */
  554.         if (mp->newrelspec == M_ORDER)
  555.             LidKey[NLidKeys++] = i;
  556.         if (!sort_only && mp->newrelspec != M_ORDER)
  557.         {
  558.             d->relxtra[i] = keyno;
  559.             keywid += (d->relfrml[i] & I1MASK);
  560.         }
  561.         if (d->relgiven[i])
  562.         {
  563.             closeall(0l, 0l);
  564.             return (error(DUPKEY, relname, cp, 0));    /* duplicate attribute */
  565.         }
  566.         d->relgiven[i] = as_ds == 0 ? keyno : -keyno;
  567.     }
  568.     pv--;    /* back up one to point to "-1" terminator */
  569.  
  570.  
  571.     if (abs(d->reldum.relspec) == M_ISAM && keywid > (MAXTUP / 2 - 4))
  572.     {
  573.         closeall(0l, 0l);
  574.         return (error(TOOWIDEISAM, relname, iocv(keywid), 0));
  575.     }
  576.  
  577.     /* if a heap, there can be no keys */
  578.     if (!mp->yeskeys && keyno != 0)
  579.     {
  580.         closeall(0l, 0l);
  581.         return (error(NOKEYSHEAP, relname, mp->type, 0));    /* no keys allowed on heap */
  582.     }
  583.     /* fill out default sort on remainder of keys */
  584.     if (mp->yeskeys)
  585.         for (i = 1; i <= d->reldum.relatts; i++)
  586.             if (d->relgiven[i] == 0)
  587.                 d->relgiven[i] = ++keyno;
  588.     *ppv = pv;
  589.     return (0);
  590. }
  591.  
  592.  
  593. /*
  594. **    MODSEQKEY - verify that sequence specified is valid
  595. **
  596. **    Parameters:
  597. **        domain - list of domains
  598. **        relname - relation name
  599. **        seq_ok - whether it is ok to specify the sequence
  600. **                ascending or descending
  601. **
  602. **    Return Codes:
  603. **        0 - ok
  604. **        > 0 - error in sequence specified
  605. **
  606. **    Called by:
  607. **        getkeys
  608. */
  609. modseqkey(domain, relname, seq_ok)
  610. char    *domain;
  611. char    *relname;
  612. int    seq_ok;
  613. {
  614.     register char    *cp, c;
  615.     register int    ret;
  616.  
  617.     ret = 0;
  618.  
  619.     for (cp = domain; c = *cp++; )
  620.         if (c == ':')
  621.             break;
  622.  
  623.     if (c != '\0')
  624.     {
  625.         /* replace ":" with null */
  626.         *(cp - 1) = '\0';
  627.  
  628.         /* verify sequence is valid */
  629.         if (!seq_ok)
  630.         {
  631.             closeall(0l, 0l);
  632.             ret = error(BADSEQSPEC, relname, cp, domain, 0);
  633.         }
  634.         else if (sequal("descending", cp) || sequal("d", cp))
  635.             ret = -1;
  636.         else if (!(sequal("ascending", cp) || sequal("a", cp)))
  637.         {
  638.             closeall(0l, 0l);
  639.             ret = error(INVALIDSEQ, relname, cp, domain, 0);
  640.         }
  641.     }
  642.  
  643.     return (ret);
  644. }
  645. /*
  646. **    GETFILL -- Get fill factor and minimum pages parameters
  647. **        from argument list, convert them from ascii to integer
  648. **        and store them in global variables.  If the global
  649. **        variable for the corresponding parameter is zero,
  650. **        it means that that parameter is not allowed and an
  651. **        error is generated.
  652. */
  653.  
  654. /*ARGSUSED*/
  655. getfill(d, pv, rel, mp)
  656. DESC        *d;
  657. register PARM    *pv;
  658. char        *rel;
  659. struct modtab    *mp;
  660. {
  661.     register char        *p1;
  662.     register int        err;
  663.     char            *p2;
  664.     int            i, j;
  665.     int            fill_flag, min_flag, max_flag, lid_flag[MAXLID];
  666.  
  667.     err = 0;
  668.     fill_flag = min_flag = max_flag = FALSE;
  669.     for (i = 0; i < d->reldum.reldim; ++i)
  670.         lid_flag[i] = FALSE;
  671.  
  672.     while ((p1 = (pv++)->pv_val.pv_str) != (char *)NULL)
  673.     {
  674.         p2 = (pv++)->pv_val.pv_str;
  675.         if (sequal(p1, "fillfactor"))
  676.         {
  677.             if (F_fac == 0 || fill_flag)
  678.             {
  679.                 err = NOTALLOWED;
  680.                 break;
  681.             }
  682.             p1 = p2;
  683.             F_fac = atoi(p1);
  684.             if (F_fac > 100 || F_fac < 1)
  685.             {
  686.                 err = FILLBOUND;
  687.                 break;
  688.             }
  689.             fill_flag = TRUE;
  690.             continue;
  691.         }
  692.         if (sequal(p1, "minpages"))
  693.         {
  694.             if (Mn_pages == 0 || min_flag)
  695.             {
  696.                 err = NOTALLOWED;
  697.                 break;
  698.             }
  699.             p1 = p2;
  700.             Mn_pages = atoi(p1);
  701.             if (Mn_pages < 1)
  702.             {
  703.                 err = MINPGBOUND;
  704.                 break;
  705.             }
  706.             if (max_flag && (Mn_pages > Mx_pages))
  707.             {
  708.                 err = MINGTMAX;
  709.                 break;
  710.             }
  711.             min_flag = TRUE;
  712.             continue;
  713.         }
  714.         if (sequal(p1, "maxpages"))
  715.         {
  716.             if (Mx_pages == 0 || max_flag)
  717.             {
  718.                 err = NOTALLOWED;
  719.                 break;
  720.             }
  721.             p1 = p2;
  722.             Mx_pages = atoi(p1);
  723.             if (Mx_pages < 1)
  724.             {
  725.                 err = MAXPGBOUND;
  726.                 break;
  727.             }
  728.             if (min_flag && (Mn_pages > Mx_pages))
  729.             {
  730.                 err = MINGTMAX;
  731.                 break;
  732.             }
  733.             max_flag = TRUE;
  734.             continue;
  735.         }
  736.         for ( i  = 1; i <= d->reldum.reldim && !err; ++i)
  737.             if (sequal(p1, ztack("lid", iocv(i))))
  738.             {
  739.                 if (lid_flag[i-1] || *Lid[i-1] == (char *)NULL)
  740.                 {
  741.                     err = NOTALLOWED;
  742.                     break;
  743.                 }
  744.                 for (j = 0; j < d->reldum.reldim; ++j)
  745.                     if (i - 1 != j && sequal(p2, Lid[j]) && lid_flag[j])
  746.                     {
  747.                         err = NOTALLOWED;
  748.                         break;
  749.                     }
  750.                 p1 = p2;
  751.                 smove(p1, Lid[i - 1]);
  752.                 lid_flag[i - 1] = TRUE;
  753.                 break;
  754.             }
  755.             if (err)
  756.                 break;
  757.         if (i <= d->reldum.reldim)
  758.             continue;
  759.         err = NEEDFILL;
  760.         break;
  761.     }
  762.     if (err)
  763.     {
  764.         closeall(0l, 0l);
  765.         return (error(err, rel, p1, 0));
  766.     }
  767.     return (0);
  768. }
  769. /*
  770. **  MAKE_NEWREL -- Create a file for the modified relation
  771. **    and build one or more primary pages for the
  772. **    relation based on its storage structure and the
  773. **    number of tuples it must hold.
  774. */
  775.  
  776. make_newrel(desc)
  777. register DESC    *desc;
  778. {
  779.     register int    tups_p_page;
  780.     int        width;
  781.  
  782.     concat(MODTEMP, Fileset, Mod_info.reltemp);
  783.     close(creat(Mod_info.reltemp, FILEMODE));
  784.     if ((desc->relfp = open(Mod_info.reltemp, O_RDWR)) < 0)
  785.         syserr("MAKE_NEWREL: open %.14s %d", Mod_info.reltemp, desc->relfp);
  786.     desc->relopn = (desc->relfp + 1) * -5;
  787.     desc->reldum.relprim = 1;
  788.     if (abs(desc->reldum.relspec) == M_HASH && F_fac > 0 && Mn_pages > 0)
  789.     {
  790.         /*
  791.         ** Determine the number of primary pages. The following
  792.         ** first determines the number of tuples/page which the
  793.         ** relation should have in order to get the requested
  794.         ** fillfactor. Then that number is divided into the
  795.         ** number of tuples to get the number of primary pages.
  796.         ** To avoid round off, it must guaranteed that the
  797.         ** number of tuples per page must be at least 1.
  798.         **
  799.         ** primary_pages = #tuples / (#tuples/page * fillfactor)
  800.         */
  801.         width = desc->reldum.relwid + 2 - LIDSIZE * desc->reldum.reldim;
  802.         tups_p_page = (((MAXTUP+2) / width) * F_fac) / 100;
  803.         if (tups_p_page == 0)
  804.             tups_p_page = 1;
  805.          /* we add one to simulate a ceiling function */
  806.         desc->reldum.relprim = desc->reldum.reltups / tups_p_page + 1;
  807.         if (desc->reldum.relprim < Mn_pages)
  808.             desc->reldum.relprim = Mn_pages;
  809.         if (Mx_pages > 0 && desc->reldum.relprim > Mx_pages)
  810.             desc->reldum.relprim = Mx_pages;
  811. #        ifdef xZTR1
  812.         if (tTf(36, 0))
  813.             printf("using %ld prim pages\n", desc->reldum.relprim);
  814. #        endif
  815.     }
  816.     desc->reldum.reltups = 0;
  817.     return (0);
  818. }
  819. /*
  820. **    SORTREL - Call KSORT to sort the given relation.  SORTREL
  821. **        sets up the descriptor struct specifying the sort
  822. **        keys and tells KSORT whether or not the hash key should
  823. **        be included as a sort key.
  824. */
  825.  
  826. sortrel(odesc, desc)
  827. DESC        *odesc;
  828. register DESC    *desc;
  829. {
  830.     extern char    *Pathname;
  831.     register int    i;
  832.     char        buf[50];
  833.     DESC        tempdesc;
  834.     char        *temp;
  835.     int        len;
  836.     short        smalli;
  837.  
  838.     concat(ISAM_SORTED, Fileset, Mod_info.outfile);
  839.     if (close(creat(Mod_info.outfile, FILEMODE)))
  840.         syserr("SORTREL: creat %.14s", Mod_info.outfile);
  841.     bmove(odesc, &tempdesc, sizeof *odesc);
  842.     for (i = 1; i <= desc->reldum.relatts; ++i)
  843.     /* set up temporary descriptor for ksort with new keyed fields */
  844.     {
  845.         tempdesc.relxtra[i] = desc->relxtra[i];
  846.         tempdesc.relgiven[i] = desc->relgiven[i];
  847.     }
  848.  
  849.     if (abs(desc->reldum.relspec) == M_HASH && !desc->reldum.reldim)
  850.     {
  851.         /* sort on hash bucket first, (if ordering sort on ordering key, not bucket) */
  852.         tempdesc.relgiven[0] = 1;
  853.         for (i = 1; i <= desc->reldum.relatts; i++)
  854.             tempdesc.relgiven[i]++;
  855.     }
  856.  
  857. # ifdef xZTR2
  858.     if (tTf(36, 4))
  859.     {
  860.         printf("sortrel: ");
  861.         printdesc(&tempdesc);
  862.     }
  863. # endif
  864.  
  865.     /* flush buffers used by modify so that ksort can't look at them */
  866.     flush_rel(desc, TRUE);
  867.     resetacc(NULL);
  868.  
  869.     /* copy Fileset so it can't get trashed */
  870.  
  871.     len = length(Fileset) + 1;
  872.     temp = (char *) need(Qbuf, len);
  873.     bmove(Fileset, temp, len);
  874.  
  875.     initp();
  876.     setp(PV_STR, temp);
  877.     setp(PV_STR, Mod_info.infile);
  878.     setp(PV_STR, Mod_info.outfile);
  879.  
  880.     /* Descriptor for new relation */
  881.     setp(PV_STR, tempdesc.reldum.relid);
  882.     setp(PV_STR, tempdesc.reldum.relowner);
  883.     setp(PV_INT, tempdesc.reldum.relspec);
  884.     setp(PV_INT, tempdesc.reldum.relindxd);
  885.     setp(PV_INT, tempdesc.reldum.relstat2);
  886.     setp(PV_INT, tempdesc.reldum.relstat);
  887.     setp(PV_INT, (short) tempdesc.reldum.relsave);
  888.     setp(PV_INT, (short) tempdesc.reldum.reltups);
  889.     setp(PV_INT, tempdesc.reldum.relatts);
  890.     setp(PV_INT, tempdesc.reldum.relwid);
  891.     setp(PV_INT, (short) tempdesc.reldum.relprim);
  892.     setp(PV_INT, (short) tempdesc.reldum.relfree);
  893.     setp(PV_INT, (short) tempdesc.reldum.relstamp);
  894.     setp(PV_INT, tempdesc.reldum.reldim);
  895.  
  896.     setp(PV_STR, tempdesc.relvname);
  897.     setp(PV_INT, tempdesc.relfp);
  898.     setp(PV_INT, tempdesc.relopn);
  899.     setp(PV_INT, (short) tempdesc.reladds);
  900.     setp(PV_INT, tempdesc.reltid.ltid);
  901.     for (i = 0; i <= tempdesc.reldum.relatts; ++i)
  902.     {
  903.         smalli = (short) tempdesc.reloff[i];
  904.         setp(PV_INT, smalli);
  905.         smalli = (short) tempdesc.relfrmt[i];
  906.         setp(PV_INT, smalli);
  907.         smalli = (short) tempdesc.relfrml[i];
  908.         setp(PV_INT, smalli);
  909.         smalli = (short) tempdesc.relxtra[i];
  910.         setp(PV_INT, smalli);
  911.         smalli = (short) tempdesc.relgiven[i];
  912.         setp(PV_INT, smalli);
  913.     }
  914.  
  915.     if (tempdesc.reldum.reldim > 0)
  916.     {
  917.         setp(PV_STR, odesc->relbtree->reldum.relid);
  918.         setp(PV_STR, odesc->relbtree->reldum.relowner);
  919.         setp(PV_INT, odesc->relbtree->reldum.relspec);
  920.         setp(PV_INT, odesc->relbtree->reldum.relindxd);
  921.         setp(PV_INT, odesc->relbtree->reldum.relstat2);
  922.         setp(PV_INT, odesc->relbtree->reldum.relstat);
  923.         setp(PV_INT, (short) odesc->relbtree->reldum.relsave);
  924.         setp(PV_INT, (short) odesc->relbtree->reldum.reltups);
  925.         setp(PV_INT, odesc->relbtree->reldum.relatts);
  926.         setp(PV_INT, odesc->relbtree->reldum.relwid);
  927.         setp(PV_INT, (short) odesc->relbtree->reldum.relprim);
  928.         setp(PV_INT, (short) odesc->relbtree->reldum.relfree);
  929.         setp(PV_INT, (short) odesc->relbtree->reldum.relstamp);
  930.         setp(PV_INT, odesc->relbtree->reldum.reldim);
  931.  
  932.         setp(PV_STR, odesc->relbtree->relvname);
  933.         setp(PV_INT, odesc->relbtree->relfp);
  934.         setp(PV_INT, odesc->relbtree->relopn);
  935.         setp(PV_INT, (short) odesc->relbtree->reladds);
  936.         setp(PV_INT, odesc->relbtree->reltid.ltid);
  937.  
  938.         for (i = 0; i <= odesc->relbtree->reldum.relatts; ++i)
  939.         {
  940.             smalli = (short) odesc->relbtree->reloff[i];
  941.             setp(PV_INT, smalli);
  942.             smalli = (short) odesc->relbtree->relfrmt[i];
  943.             setp(PV_INT, smalli);
  944.             smalli = (short) odesc->relbtree->relfrml[i];
  945.             setp(PV_INT, smalli);
  946.             smalli = (short) odesc->relbtree->relxtra[i];
  947.             setp(PV_INT, smalli);
  948.             smalli = (short) odesc->relbtree->relgiven[i];
  949.             setp(PV_INT, smalli);
  950.         }
  951.     }
  952.  
  953.     call(mdKSORT, NULL);
  954.  
  955.     /* flush buffers used by ksort so that modify can't look at them */
  956.     flush_rel(desc, TRUE);
  957.     resetacc(NULL);
  958.  
  959. # ifdef xZTR1
  960.     if (tTf(36,9))
  961.         printf("SORTREL: done calling ksort\n");
  962. #endif
  963.     return (0);
  964. }
  965. /*
  966. **    SORT_ISAM -- Sorts an isam relation back to its original order
  967. **    so that it will be inserted into the relation in the proper order.
  968. **    It is presently not in order because it has been sorted according
  969. **    to a specified field for ordering.
  970. */
  971. sort_isam(sdesc, desc)
  972. DESC *sdesc;
  973. DESC *desc;
  974. {
  975.     long        lid[MAXLID];
  976.     register int    i, j, k;
  977.     char        tup_buf[MAXTUP], last_tup[MAXTUP], *dp, *sp;
  978.     FILE        *sfp, *fp;
  979.     TID        tid, tidpos;
  980.     DESC        tempdesc;
  981.     int        w;
  982.  
  983.     if (desc->reldum.reldim > 0)
  984.         Btree_fd = desc->btree_fd;
  985.     concat(STEMP, Fileset, Mod_info.temp_sort);
  986.     if ((sfp = fopen(Mod_info.temp_sort, "w")) == (char *)NULL)
  987.         syserr("sort_isam: can't open %s", Mod_info.temp_sort);
  988.     if ((fp = fopen(Mod_info.outfile, "r")) == NULL)
  989.         syserr("sort_isam: can't open %s", Mod_info.outfile);
  990.     for (i = 0; i < desc->reldum.reldim; lid[i++] = 0);
  991.     /* create input file for sort with proper lid attached to each tuple */
  992.     w = sdesc->reldum.relwid - LIDSIZE * sdesc->reldum.reldim;
  993.     for ( ; ; )
  994.     {
  995.         i = fread(tup_buf, 1, sdesc->reldum.relwid, fp);
  996.         if (i == 0)
  997.             break;
  998.         if (i != sdesc->reldum.relwid)
  999.             syserr("sort_isam: read error in %s", Mod_info.outfile);
  1000.         for (j = 0; j < desc->reldum.reldim; ++j)
  1001.             if (j < NLidKeys && j < desc->reldum.reldim - 1)
  1002.             {
  1003.                 dp = tup_buf + (sdesc->reloff[LidKey[j]] & I1MASK);
  1004.                 sp = last_tup + (sdesc->reloff[LidKey[j]] & I1MASK);
  1005.                 if (!bequal(dp, sp, sdesc->relfrml[LidKey[j]]) || !lid[j])
  1006.                 {
  1007.                     ++lid[j];
  1008.                     for (k = j + 1; k < desc->reldum.reldim; ++k)
  1009.                         lid[k] = 0;
  1010.                     break;
  1011.                 }
  1012.             }
  1013.             else
  1014.             {
  1015.                 if (!lid[0])
  1016.                 {
  1017.                     lid[0] = 1;
  1018.                     if (!(desc->reldum.reldim - 1))
  1019.                         break;
  1020.                 }
  1021.                 ++lid[desc->reldum.reldim - 1];
  1022.                 break;
  1023.             }
  1024.         bmove(tup_buf, last_tup, sdesc->reldum.relwid);
  1025.         /* reserve a slot in btree for tuple */
  1026.         insert_mbtree(desc, Mod_info.btree, lid, &tid, &tidpos);
  1027.         bmove(lid, tup_buf + w, LIDSIZE * desc->reldum.reldim);
  1028.         if (fwrite(tup_buf, 1, sdesc->reldum.relwid + LIDSIZE * desc->reldum.reldim, sfp) != sdesc->reldum.relwid + LIDSIZE * desc->reldum.reldim)
  1029.             syserr("sort_isam: write error in %s", Mod_info.temp_sort);
  1030.     }
  1031.     fclose(fp);
  1032.     fclose(sfp);
  1033.     /* set up new descriptor accounting for lid field */
  1034.     bmove(sdesc, &tempdesc, sizeof *sdesc);
  1035.     tempdesc.reldum.relspec = M_ORDER;
  1036.     for (i = 0; i < desc->reldum.reldim; ++i)
  1037.     {
  1038.         tempdesc.reldum.relwid += LIDSIZE;
  1039.         ++tempdesc.reldum.relatts;
  1040.         tempdesc.reloff[tempdesc.reldum.relatts] = tempdesc.reldum.relwid - LIDSIZE;
  1041.         tempdesc.relfrmt[tempdesc.reldum.relatts] = INT;
  1042.         tempdesc.relfrml[tempdesc.reldum.relatts] = LIDSIZE;
  1043.     }
  1044.     j = 0;
  1045.     /* use old keying attributes for specifying sort order */
  1046.     clearkeys(&tempdesc);
  1047.     for (i = 1; i <= sdesc->reldum.relatts; ++i)
  1048.         if (sdesc->relxtra[i])
  1049.         {
  1050.             tempdesc.relgiven[i] = sdesc->relxtra[i];
  1051.             ++j;
  1052.         }
  1053.     for (i = 1; i <= tempdesc.reldum.relatts; ++i)
  1054.         if (!tempdesc.relgiven[i])
  1055.             tempdesc.relgiven[i] = ++j;
  1056.     sortfile(Mod_info.temp_sort, &tempdesc, FALSE);
  1057.     if (unlink(Mod_info.outfile) < 0)
  1058.         syserr("can't unlink %s", Mod_info.outfile);
  1059.     if (link(ztack(REPL_OUT, Fileset), Mod_info.outfile) == -1)
  1060.         syserr("can't link %s to %s", ztack(REPL_OUT, Fileset), Mod_info.outfile);
  1061.     if (unlink(Mod_info.temp_sort) < 0)
  1062.         syserr("sort_isam: can't unlink %s", Mod_info.temp_sort);
  1063.     if (unlink(ztack(REPL_OUT, Fileset)) < 0)
  1064.         syserr("sort_isam: can't unlink replout file");
  1065. }
  1066. /*
  1067. **    FILL_REL -- Fill the new relation with tuples from either
  1068. **        the old relation or the output file of KSORT.
  1069. */
  1070.  
  1071. fill_rel(sdesc, desc, sortit)
  1072. register DESC    *sdesc, *desc;
  1073. char            sortit;
  1074. {
  1075.     register int    i;
  1076.     char        tup_buf[MAXTUP], last_tup[MAXTUP], tup[2 * LIDSIZE]; 
  1077.     char        junk[4], newreltype, anytups, chkdups;
  1078.     int        need, j, k;
  1079.     long        lnum, lid[MAXLID], l, page, t;
  1080.     TID        tid, stid, stidlim, ntid, tidpos, btid;
  1081.     FILE        *fp, *spfp;
  1082.     char        *dp, *sp;
  1083.     int        w, temp;
  1084.     struct locator    tidloc;
  1085.  
  1086.     newreltype = abs(desc->reldum.relspec);
  1087.     if (sortit)
  1088.     {
  1089.         if ((fp = fopen(Mod_info.outfile, "r")) == NULL)
  1090.             syserr("FILL_REL: fopen %.14s", Mod_info.outfile);
  1091.     }
  1092.     else
  1093.     {
  1094.         cleanrel(sdesc);    /* make sure each page is read fresh */
  1095.         find(sdesc, NOKEY, &stid, &stidlim);
  1096.     }
  1097.     if (newreltype == M_ISAM && (NLidKeys > 0 || !desc->reldum.reldim))
  1098.     {
  1099.         lnum = 0;
  1100.         stuff_page(&tid, &lnum);
  1101.         tid.line_id = 0;
  1102.         get_page(desc, &tid);
  1103.         concat(ISAM_SPOOL, Fileset, Mod_info.spfile);
  1104.         /* assume that spool file is not needed */
  1105.         spfp = NULL;
  1106.         Mod_info.spflag = FALSE;
  1107.         if (F_fac == 0)
  1108.             F_fac = 100;
  1109.         /* setup relgiven field for kcompare later on */
  1110.         for (i = 1; i <= desc->reldum.relatts; i++)
  1111.             desc->relgiven[i] = desc->relxtra[i];
  1112.         if (desc->reldum.reldim)
  1113.             Btree_fd = desc->btree_fd;
  1114.     }
  1115.     desc->reladds = 0;
  1116.     for (i = 0; i < desc->reldum.reldim; lid[i++] = 0)
  1117.         continue;
  1118.     anytups = FALSE;
  1119.     chkdups = !sortit && (newreltype != M_ORDER);
  1120. # ifdef xZTR2
  1121.     if (tTf(36, 3))
  1122.     {
  1123.         printf("  FILLREL: ");
  1124.         printdesc(sdesc);
  1125.         printdesc(desc);
  1126.     }
  1127. # endif
  1128.     for (;;)
  1129.     {
  1130.         w = (newreltype == M_ISAM) ? sdesc->reldum.relwid + desc->reldum.reldim * LIDSIZE : sdesc->reldum.relwid;
  1131.         if (sortit)
  1132.         {
  1133.             i = fread(tup_buf, 1, w, fp);
  1134.             if (i == 0)
  1135.                 break;
  1136.             if (i != w)
  1137.                 syserr("FILL_REL: fread A %d", i);
  1138.             if (newreltype == M_HASH && !desc->reldum.reldim)
  1139.                 if (fread(junk, 1, 4, fp) != 4)
  1140.                     syserr("FILL_REL: fread B");
  1141.         }
  1142.         else
  1143.         {
  1144. #            ifdef xZTR2
  1145.             if (tTf(36, 1))
  1146.             {
  1147.                 printf("FILL_REL: stid ");
  1148.                 dumptid(&stid);
  1149.                 printf("FILL_REL: stidlim ");
  1150.                 dumptid(&stidlim);
  1151.             }
  1152. #            endif
  1153.             i = get(sdesc, &stid, &stidlim, tup_buf, TRUE);
  1154. #            ifdef xZTR2
  1155.             if (tTf(36, 1))
  1156.             {
  1157.                 printf("FILLREL: get %d ", i);
  1158.                 printup(sdesc, tup_buf);
  1159.             }
  1160. #            endif
  1161.             if (i < 0)
  1162.                 syserr("FILL_REL: get %d", i);
  1163.             if (i == 1)
  1164.                 break;
  1165.         }
  1166.         if (newreltype != M_ISAM || (newreltype == M_ISAM && NLidKeys == 0 && desc->reldum.reldim > 0))
  1167.         {
  1168.             for (j = 0; j < desc->reldum.reldim; ++j)
  1169.                 if (j < NLidKeys && j < desc->reldum.reldim - 1)
  1170.                 {
  1171.                     dp = tup_buf + (sdesc->reloff[LidKey[j]] & I1MASK);
  1172.                     sp = last_tup + (sdesc->reloff[LidKey[j]] & I1MASK);
  1173.                     if (!bequal(dp, sp, sdesc->relfrml[LidKey[j]]) || !lid[j])
  1174.                     {
  1175.                         ++lid[j];
  1176.                         for (k = j + 1; k < desc->reldum.reldim; ++k)
  1177.                             lid[k] = 0;
  1178.                         break;
  1179.                     }
  1180.                 }
  1181.                 else
  1182.                 {
  1183.                     if (!lid[0])
  1184.                     {
  1185.                         lid[0] = 1;
  1186.                         if (!(desc->reldum.reldim -1))
  1187.                             break;
  1188.                     }
  1189.                     ++lid[desc->reldum.reldim - 1];
  1190.                     break;
  1191.                 }
  1192.             Btree_fd = desc->btree_fd;
  1193.             if (!desc->reldum.reldim || NLidKeys > 0)
  1194.             {
  1195.                 /* assume unordered so btree inserts done
  1196.                 ** separately */
  1197.                 temp = 0;
  1198.                 if (desc->reldum.reldim > 0)
  1199.                 {
  1200.                     temp = desc->reldum.reldim;
  1201.                     desc->reldum.reldim = 0;
  1202.                     desc->reldum.relwid -= temp * LIDSIZE;
  1203.                 }
  1204.                 if ((i = insert(desc, &tid, tup_buf, chkdups)) < 0)
  1205.                     syserr("FILL_REL: insert %d", i);
  1206.                 if (NLidKeys > 0)
  1207.                 {
  1208.                     bmove(&tid, &stid, LIDSIZE);
  1209.                     desc->reldum.reldim = temp;
  1210.                     desc->reldum.relwid += temp * LIDSIZE;
  1211.                     insert_mbtree(desc, Mod_info.btree, lid, &tid, &tidpos);
  1212.                 }
  1213.             }
  1214.             if (desc->reldum.reldim && !NLidKeys)
  1215.             {
  1216.                 /* new relation not changed, only lids added */
  1217.                 page = RT;
  1218.                 for (j = 0; j < desc->reldum.reldim - 1; ++j)
  1219.                 {
  1220.                     if (!lid[j])
  1221.                         lid[j] = 1;
  1222.                     if ((t = get_tid(page, lid[j], &tidloc)) < 0)
  1223.                     {
  1224.                         insert_btree(Mod_info.btree, page, lid[j], &ntid, &tidpos, j + 2);
  1225.                         bmove(&ntid, &page, LIDSIZE);
  1226.                     }
  1227.                     else
  1228.                         bmove(&t, &page, LIDSIZE);
  1229.                 }
  1230.                 insert_btree(Mod_info.btree, page, lid[abs(desc->reldum.reldim) - 1], &stid, &tidpos, FALSE);
  1231.             }
  1232.             bmove(tup_buf, last_tup, sdesc->reldum.relwid);
  1233.             if (desc->reldum.reldim > 0)
  1234.             {
  1235.                 dp = tup_buf + desc->reldum.relwid - desc->reldum.reldim * LIDSIZE;
  1236.                 bmove(lid, dp, LIDSIZE * desc->reldum.reldim);
  1237.             }
  1238. #            ifdef xZTR2
  1239.             if (tTf(36, 2))
  1240.             {
  1241.                 printf("FILL_REL: insert ");
  1242.                 printup(desc, tup_buf);
  1243.                 printf("FILL_REL: insert ret %d at", i);
  1244.                 dumptid(&tid);
  1245.             }
  1246. #            endif
  1247.             continue;
  1248.         }
  1249.         if (anytups)
  1250.             i = kcompare(desc, tup_buf, last_tup);
  1251.         else
  1252.         {
  1253.             anytups = TRUE;
  1254.             i = 1;
  1255.         }
  1256.         bmove(tup_buf, last_tup, desc->reldum.relwid);
  1257.         need = canonical(desc, tup_buf);
  1258.         if (i == 0 && need > space_left(Acc_head))
  1259.         {
  1260.             /* spool out this tuple. will go on overflow page later */
  1261.             if (spfp == NULL)
  1262.             {
  1263.                 if ((spfp = fopen(Mod_info.spfile, "w")) == NULL)
  1264.                     syserr("FILL_REL: fopen %.14s", Mod_info.spfile);
  1265.                 Mod_info.spflag = TRUE;
  1266.             }
  1267.             if (fwrite(tup_buf, 1, desc->reldum.relwid, spfp) != desc->reldum.relwid)
  1268.                 syserr("FILL_REL: putb spool");
  1269.             continue;
  1270.         }
  1271.         j = (100 - F_fac) * MAXTUP / 100;
  1272.         if (j < need)
  1273.             j = need;
  1274.         if (i != 0 && j > space_left(Acc_head))
  1275.         {
  1276.             if (i = add_prim(desc, &tid))
  1277.                 syserr("FILL_REL: force ovflo %d", i);
  1278.         }
  1279.         tid.line_id = newlino(need);
  1280.         put_tuple(&tid, Acctuple, need);
  1281.         if (NLidKeys > 0)
  1282.         {
  1283.             bmove(tup_buf + desc->reldum.relwid - LIDSIZE * desc->reldum.reldim, lid, LIDSIZE * desc->reldum.reldim);
  1284.             page = RT;
  1285.             for (j = 0; j < desc->reldum.reldim; ++j)
  1286.             {
  1287.                 if ((t = get_tid(page, lid[j], &tidloc)) < 0)
  1288.                     syserr("get_tid error in modify isam ordered");
  1289.                 page = t;
  1290.             }
  1291.             stuff_page(&btid, &tidloc.pageno);
  1292.             btid.line_id = tidloc.page.node.leafnode.tid_loc[tidloc.offset];
  1293.             /* place proper tid in tree */
  1294.             replace_btree(tid, &btid);
  1295.         }
  1296.         desc->reladds++;
  1297.     }
  1298.     if (sortit)
  1299.     {
  1300.         fclose(fp);
  1301.         unlink(Mod_info.outfile);
  1302.     }
  1303.     if (newreltype == M_ISAM && desc->reldum.reldim <= 0)
  1304.     {
  1305.         if (i = pageflush(Acc_head))
  1306.             syserr("fill_rel:pg clean %d", i);
  1307.         if (spfp != NULL)
  1308.             fclose(spfp);
  1309.     }
  1310.     if (!desc->reldum.reldim || NLidKeys > 0)
  1311.         desc->reldum.reltups = desc->reladds;
  1312.     desc->reladds = 0;
  1313.     return (0);
  1314. }
  1315.  
  1316.  
  1317. /*
  1318. **    BLDINDEX -    
  1319. **
  1320. **    Parameters:
  1321. **        d - descriptor for relation
  1322. **
  1323. **    Return Codes:
  1324. **        0 - ok
  1325. **        <0 - error
  1326. **
  1327. **    Trace Flags:
  1328. **        Z38.7, Z38.8
  1329. **
  1330. **    Called by:
  1331. **        modify
  1332. **
  1333. */
  1334. bldindex(d)
  1335. register DESC    *d;
  1336. {
  1337.     register TID    *tid;
  1338.     register int    tmp;
  1339.     TID        tidx;
  1340.     struct accbuf    dirbuf;
  1341.     int        keywid, level, savespec, keyx[MAXDOM];
  1342.     int        offset, len;
  1343.     char        tuple[MAXTUP], temptup[MAXTUP], *key;
  1344.     long        pageid, start, stop, newstart, newstop;
  1345.  
  1346.     tid = &tidx;
  1347.     keywid = 0;
  1348.     for (tmp = 0; tmp < MAXDOM; tmp++)
  1349.         keyx[tmp] = 0;
  1350.     for (tmp = 1; tmp <= d->reldum.relatts; tmp++)
  1351.         if (d->relxtra[tmp] > 0)
  1352.         {
  1353.             keyx[d->relxtra[tmp] - 1] = tmp;
  1354.             keywid += d->relfrml[tmp] & I1MASK;
  1355.         }
  1356.  
  1357.     /* Determine the last page of the relation. This will
  1358.     ** only work if all pages have been written out. Fill_rel
  1359.     ** must guarantee that all pages have been written
  1360.     */
  1361.     level = 0;
  1362.     last_page(d, tid, 0);
  1363.     pluck_page(tid, &stop);
  1364.     start = 0;
  1365.     dirbuf.filedesc = d->relfp;
  1366.     dirbuf.rel_tupid = d->reltid.ltid;
  1367.     savespec = d->reldum.relspec;
  1368.     for (;;)
  1369.     {
  1370. #        ifdef xZTR2
  1371.         if (tTf(38, 7))
  1372.             printf("isam: level %d\n", level);
  1373. #        endif
  1374.         dirbuf.ovflopg = start;
  1375.         dirbuf.mainpg = level;
  1376.         dirbuf.thispage = stop + 1;
  1377.         dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf);
  1378.         offset = dirbuf.linetab[0];
  1379.         dirbuf.bufstatus = BUF_DIRTY | BUF_DIRECT;
  1380.  
  1381.         dirbuf.nxtlino = 0;
  1382.         newstart = stop + 1;
  1383.         newstop = newstart;
  1384.         for (pageid = start; pageid <= stop; pageid++)
  1385.         {
  1386. #            ifdef xZTR2
  1387.             if (tTf(38, 8))
  1388.                 printf("isam:get key from %ld\n", pageid);
  1389. #            endif
  1390.             stuff_page(tid, &pageid);
  1391.             tid->line_id = 0;
  1392.             if (tmp = get(d, tid, tid, tuple, FALSE))
  1393.             {
  1394.                 /*
  1395.                 ** If the relation is empty, then page 0 will
  1396.                 ** return AMINVL_ERR on a get(). Form a blank tuple
  1397.                 ** and use it to create a one tuple directory
  1398.                 */
  1399.                 if (pageid == 0 && tmp == AMINVL_ERR)
  1400.                 {
  1401.                     clr_tuple(d, tuple);
  1402.                 }
  1403.                 else
  1404.                 {
  1405.                     return (-2);
  1406.                 }
  1407.             }
  1408.  
  1409.             /*
  1410.             ** If this is the first level then form the tuple
  1411.             ** from the mainpage of the relation. Otherwise
  1412.             ** the tuple is the first tuple of a directory page
  1413.             ** and it is already correctly formed.
  1414.             */
  1415.             if (level == 0)
  1416.             {
  1417.                 key = temptup;
  1418.                 for (tmp = 0; keyx[tmp] != 0; tmp++)
  1419.                 {
  1420.                     len = d->relfrml[keyx[tmp]] & I1MASK;
  1421.                     bmove(&tuple[d->reloff[keyx[tmp]]], key, len);
  1422.                     key += len;
  1423.                 }
  1424.                 key = temptup;
  1425.             }
  1426.             else
  1427.                 key = tuple;
  1428.  
  1429.             if (keywid > space_left(&dirbuf))
  1430.             {
  1431.                 if (pageflush(&dirbuf))
  1432.                     return (-3);
  1433.                 dirbuf.thispage++;
  1434.                 newstop = dirbuf.thispage;
  1435.                 dirbuf.ovflopg = pageid;
  1436.                 dirbuf.linetab[0] = (short) (dirbuf.firstup - (char *) &dirbuf);
  1437.                 offset = dirbuf.linetab[0];
  1438.                 dirbuf.bufstatus = BUF_DIRTY;
  1439.                 dirbuf.nxtlino = 0;
  1440.             }
  1441.             /* copy key to directory page */
  1442.             bmove(key, (char *) &dirbuf + offset, keywid);
  1443.  
  1444.             /* update next line number */
  1445.             offset += keywid;
  1446.             dirbuf.nxtlino++;
  1447.             dirbuf.linetab[-dirbuf.nxtlino] = offset;
  1448.         }
  1449.         if (pageflush(&dirbuf))
  1450.             return (-4);
  1451.         if (newstart == newstop)
  1452.             break;
  1453.         d->reldum.relspec = abs(d->reldum.relspec);
  1454.         level++;
  1455.         start = newstart;
  1456.         stop = newstop;
  1457.     }
  1458.     d->reldum.relspec = savespec;
  1459.     d->reldum.relprim = newstart;
  1460.     return (0);
  1461. }
  1462. /*
  1463. **    UNSPOOL -- Take tuples saved in spool file and insert them
  1464. **        in new relation.  This is only for ISAM relations.
  1465. */
  1466.  
  1467. unspool(sdesc, desc)
  1468. register DESC    *sdesc, *desc;
  1469. {
  1470.     register int    i, j;
  1471.     TID        tid, btid;
  1472.     char        tup_buf[MAXTUP], tup[2 * LIDSIZE];
  1473.     FILE        *spfp;
  1474.     long        lid[MAXLID], page, t;
  1475.     int        w;
  1476.     struct locator  tidpos;
  1477.  
  1478.     w = sdesc->reldum.relwid + desc->reldum.reldim * LIDSIZE;
  1479.     if (Mod_info.spflag)
  1480.     {
  1481.         if ((spfp = fopen(Mod_info.spfile, "r")) == NULL)
  1482.             syserr("UNSPOOL: fopen spool");
  1483.         while ((i = fread(tup_buf, 1, w, spfp)) == w)
  1484.         {
  1485.             if ((i = insert(desc, &tid, tup_buf, FALSE)) < 0)
  1486.                 syserr("UNSPOOL: insert %.14s %d", desc->reldum.relid, i);
  1487.             if (NLidKeys > 0)
  1488.             {
  1489.                 bmove(tup_buf + desc->reldum.relwid - LIDSIZE * desc->reldum.reldim, lid, LIDSIZE * desc->reldum.reldim);
  1490.                 page = RT;
  1491.                 for (j = 0; j < desc->reldum.reldim; ++j)
  1492.                 {
  1493.                     if ((t = get_tid(page, lid[j], &tidpos)) < 0)
  1494.                         syserr("get_tid error in unspool");
  1495.                     page = t;
  1496.                 }
  1497.                 stuff_page(&btid, &tidpos.pageno);
  1498.                 btid.line_id = tidpos.page.node.leafnode.tid_loc[tidpos.offset];
  1499.                 replace_btree(tid, &btid);
  1500.             }
  1501.         }
  1502.         if (i != 0)
  1503.             syserr("UNSPOOL: read %d", i);
  1504.         fclose(spfp);
  1505.         unlink(Mod_info.spfile);
  1506.     }
  1507.     desc->reldum.reltups += desc->reladds;
  1508.     desc->reladds = 0;
  1509.     return (0);
  1510. }
  1511. /*
  1512. **    FILL_BATCH -- Create and fill a batch file containing the
  1513. **        updates for the system catalog so that MODIFY will
  1514. **        be recoverable if the system crashes.
  1515. */
  1516.  
  1517. fill_batch(odesc, desc)
  1518. DESC        *odesc;
  1519. register DESC    *desc;
  1520. {
  1521.     register DESC        *dessys;
  1522.     register int        i, k;
  1523.     struct relation        reltup, rkey;
  1524.     TID            tid, lotid, hitid;
  1525.     struct attribute    atttup, akey;
  1526.     int            numatts, j;
  1527.     char            prebatch[MAXNAME + 4], modbatch[MAXNAME + 4];
  1528.  
  1529.     if (bequal(desc->reldum.relid, "relation    ", 12))
  1530.     {
  1531.         clearkeys(desc);
  1532.         setkey(desc, &rkey, desc->reldum.relid, RELID);
  1533.         setkey(desc, &rkey, desc->reldum.relowner, RELOWNER);
  1534.         if (i = getequal(desc, &rkey, &reltup, &tid))
  1535.             syserr("FILL_BATCH: geteq rel rel %d", i);
  1536.         bmove(&tid, &desc->reltid, sizeof desc->reltid);
  1537.     }
  1538.     else
  1539.         bmove(&odesc->reltid, &desc->reltid, sizeof desc->reltid);
  1540.     resetacc(Acc_head);
  1541.     concat(MOD_PREBATCH, Fileset, prebatch);
  1542.     close(creat(prebatch, FILEMODE));
  1543.     if ((Batch_fp = open(prebatch, O_RDWR)) < 0)
  1544.         syserr("FILL_BATCH: open %.14s %d", prebatch, Batch_fp);
  1545.     smove(Fileset, Batchbuf.file_id);
  1546.     Batch_cnt = 0;
  1547.     wrbatch(desc, sizeof *desc);
  1548.     if (bequal(desc->reldum.relid, "attribute   ", 12))
  1549.         dessys = desc;
  1550.     else
  1551.         dessys = &Admin.adattd;
  1552.     clearkeys(dessys);
  1553.     setkey(dessys, &akey, desc->reldum.relid, ATTRELID);
  1554.     setkey(dessys, &akey, desc->reldum.relowner, ATTOWNER);
  1555.     if (i = find(dessys, EXACTKEY, &lotid, &hitid, &akey))
  1556.         syserr("FILL_BATCH: find %d", i);
  1557.  
  1558.     /* if ordered relation, one of attributes is LID field */
  1559.     numatts = j = desc->reldum.relatts - desc->reldum.reldim;
  1560.  
  1561.     while(!(i = get(dessys, &lotid, &hitid, &atttup, TRUE)) && j > 0)
  1562.         if (!kcompare(dessys, &akey, &atttup))
  1563.             if (atttup.attid <= numatts)
  1564.             {
  1565.                 j--;
  1566.                 atttup.attxtra = desc->relxtra[atttup.attid];
  1567.                 wrbatch(&lotid, sizeof lotid);
  1568.                 wrbatch(&atttup, sizeof atttup);
  1569.             }
  1570.     for (k = 1; k <= desc->reldum.reldim; ++k)
  1571.     /* create new tuple corresponding to LID field; LID field is the
  1572.     ** last field of relation, a 4-byte integer 
  1573.     */
  1574.     {
  1575.         smove(desc->reldum.relid, atttup.attrelid);
  1576.         bmove(desc->reldum.relowner, atttup.attowner, 2);
  1577.         atttup.attid = numatts + k;
  1578.         smove(Lid[k - 1], atttup.attname);
  1579.         pad(atttup.attname, MAXNAME);
  1580.         atttup.attoff = desc->reldum.relwid - (desc->reldum.reldim - k + 1) * LIDSIZE;
  1581.         atttup.attfrmt = INT;
  1582.         atttup.attfrml = LIDSIZE;
  1583.         atttup.attxtra = 0;
  1584.         wrbatch(&atttup, sizeof atttup);
  1585.     }
  1586.     if (i < 0 || j > 0)
  1587.         syserr("FILL_BATCH: get att %d count %d", i, j);
  1588.     /* get rid of attribute pages */
  1589.     cleanrel(dessys);
  1590.     flushbatch();
  1591.     close(Batch_fp);
  1592.     concat(MODBATCH, Fileset, modbatch);
  1593.     if (link(prebatch, modbatch) == -1)
  1594.         syserr("FILL_BATCH: can't link %.14s %.14s",
  1595.             prebatch, modbatch);
  1596.     unlink(prebatch);
  1597.     return (0);
  1598.  
  1599. }
  1600.  
  1601. /*
  1602. **    MAKE_BSEC -- Creates the seecondary btree relation by first creating
  1603. **        a heaped relation.  The main relation tids are found by
  1604. **        scanning the leaves of the btree.  The relation is then 
  1605. **        modified to an isam relation.
  1606. */    
  1607.  
  1608. make_bsec(relname, dim)
  1609. char *relname;
  1610. int dim;
  1611. {
  1612.     PARM        pv[8];
  1613.     register int    i;
  1614.     DESC        bdesc;
  1615.     TID        tid, btid;
  1616.     long        mtid, page, t, next;
  1617.     char        tuple[2 * LIDSIZE], btree[MAXNAME], btreefile[MAXNAME + 4];
  1618.     struct locator    tidpos;
  1619.     extern char    *iocv();
  1620.     extern DESC    Reldes;
  1621.  
  1622.     pv[0].pv_val.pv_str = "0000002";
  1623.     capital(trim_relname(relname), btree);
  1624.     pv[1].pv_val.pv_str = btree;
  1625.     pv[2].pv_val.pv_str = "mtid";
  1626.     pv[3].pv_val.pv_str = "i4";
  1627.     pv[4].pv_val.pv_str = "btid";
  1628.     pv[5].pv_val.pv_str = "i4";
  1629.     pv[6].pv_type = PV_EOF;
  1630.     if (create(6, pv))
  1631.         syserr("can't create btreesec %s", pv[1].pv_val.pv_str);
  1632.     
  1633.     if (noclose(&Reldes))
  1634.         syserr("noclose in make_bsec");
  1635.  
  1636.     if (i = openr(&bdesc, OR_WRITE, btree))
  1637.         syserr("opening bsec relation %d", i);
  1638.     btreename(relname, btreefile);
  1639.     if ((Btree_fd = open(btreefile, O_RDWR)) < 0)
  1640.         syserr("make_bsec: can't open %s", btreefile);
  1641.     page = RT;
  1642.     for (i = 0; i < dim - 1; ++i)
  1643.     {
  1644.         t = get_tid(page, 1, &tidpos);
  1645.         if (t < 0)
  1646.             break;    /* lid value doesn't exist */
  1647.         bmove(&t, &page, LIDSIZE);
  1648.     }
  1649.     if (t >= 0)    /* only do inserts if there are lids! */
  1650.     {
  1651.         do
  1652.         {
  1653.             get_node(page, &tidpos.page);
  1654.             next = tidpos.page.nexttree;
  1655.             get_tid(page, 1, &tidpos);
  1656.             page = tidpos.pageno;
  1657.             for (;;)
  1658.             /* scan through leaves of btree */
  1659.             {
  1660.                 stuff_page(&btid, &page);
  1661.                 for (i = 0; i < tidpos.page.nelmts; ++i)
  1662.                 {
  1663.                     btid.line_id = tidpos.page.node.leafnode.tid_loc[i];
  1664.                     mtid = tidpos.page.node.leafnode.tid_pos[btid.line_id];
  1665.                     /* form tuple */
  1666.                     bmove(&mtid, tuple, LIDSIZE);
  1667.                     bmove(&btid, tuple + LIDSIZE, LIDSIZE);
  1668.                     if (insert(&bdesc, &tid, tuple, TRUE) < 0)
  1669.                         syserr("insert error in btreesec");
  1670.                 }
  1671.                 page = tidpos.page.node.leafnode.nextleaf;
  1672.                 if (page == NULL)
  1673.                     break;
  1674.                 else 
  1675.                     get_node(page, &tidpos.page);
  1676.             }
  1677.         } while (page = next);
  1678.     }
  1679.     close(Btree_fd);
  1680.     closer(&bdesc);
  1681.  
  1682.     /* modify to isam on mtid */
  1683.     pv[0].pv_val.pv_str = btree;
  1684.     pv[1].pv_val.pv_str = "isam";
  1685.     pv[2].pv_val.pv_str = "name";
  1686.     pv[3].pv_val.pv_str = "mtid";
  1687.     pv[4].pv_val.pv_str = "\0";
  1688.     pv[5].pv_val.pv_str = "fillfactor";
  1689.     /* use fillfactor provided for main relation */
  1690.     if (F_fac == 0)
  1691.         pv[6].pv_val.pv_str = iocv(80);
  1692.     else
  1693.         pv[6].pv_val.pv_str = iocv(F_fac);
  1694.     pv[7].pv_type = PV_EOF;
  1695.     if (modify(7, pv))
  1696.         syserr("can't modify btreesec to isam");
  1697. }
  1698.